# --*--coding=utf-8 --*--
"""
通过这个模块实现对业务数据的解析
"""
import copy
from xml.dom import minidom
from auto_test.lib.data_util import str_to_dict, upd_dict_data, bytes_to_dict
from auto_test.lib.excel_util import sheet_to_list
from auto_test.lib.file_util import get_abs_path
from auto_test.lib import jsonpath_util
from auto_test.lib.log_util import logger
from auto_test.config import CBSConfig
from auto_test.test.step.base import CBSRequest, get_user_cookie
from auto_test.test.entity.business import RequestData
from auto_test.test.entity.case import TestCase
from auto_test.test.entity.plan import TestPlan
from auto_test.test.entity.message import CbcProxyMsg
from auto_test.test.parse.key_word import action


def getRequestDataList(sheet_name=None):
    """
    获取业务对象列表
    """
    fp = get_abs_path(CBSConfig.TEST_DATA_DIR + '/请求.xlsx')
    records = sheet_to_list(fp, sheet_name)
    requestDataList = []
    for record in records:
        rd = RequestData(record['request_id'])
        rd.set_req_name(record['request_name'])
        rd.set_child_url(record['request_url'].split('/')[-1])
        rd.set_req_method(record['request_method'])
        rd.set_req_body(str_to_dict(record['request_body']))
        rd.set_res_body(str_to_dict(record['response_body']))
        requestDataList.append(rd)
    return requestDataList


def getRequestDataById(req_id, sheet_name=None):
    """
    获取业务对象通过Id
    :param req_id: 实体类的Id
    :param sheet_name:
    """
    fp = get_abs_path(CBSConfig.TEST_DATA_DIR + '/请求.xlsx')
    records = sheet_to_list(fp, sheet_name)
    for record in records:
        if record['request_id'] == req_id:
            rd = RequestData(record['request_id'])
            rd.set_req_name(record['request_name'])
            rd.set_child_url(record['request_url'].split('/')[-1])
            rd.set_req_method(record['request_method'])
            rd.set_req_body(str_to_dict(record['request_body']))
            rd.set_res_body(str_to_dict(record['response_body']))
            return rd


def getTestCaseList(sheet_name=None):
    """
    :param sheet_name:
    """
    fp = get_abs_path(CBSConfig.TEST_DATA_DIR + '/用例数据.xlsx')
    records = sheet_to_list(fp, sheet_name)
    rdList = getRequestDataList()
    testCaseList = []
    cur_case_id = None
    for record in records:
        case_id = record['case_id']
        # if 用例不在列表中，
        if (cur_case_id is None) or (cur_case_id != case_id):
            cur_case_id = case_id
            case = TestCase(case_id)
            testCaseList.append(case)
        # 处理用例涉及到的请求数据
        for rd in rdList:
            if rd.req_id == record['request_id']:
                requestData = copy.deepcopy(rd)
                requestData.set_username(record['user_name'])
                req_data_dict = str_to_dict(record['request_data'])
                # 新增响应代理报文
                cbcProxyMsg = getCbcProxyMsgById(record['msg_id'])
                # 代理报文的更新，存在全量更新的问题，待修复
                upd_msg_data = record['msg_data']
                if cbcProxyMsg is not None:
                    if upd_msg_data is not None and len(upd_msg_data) > 0:
                        cbcProxyMsg.set_msg_data(upd_dict_data(cbcProxyMsg.msg_data, record['msg_data']))
                        cbcProxyMsg.get_msg_xml(rd.req_name)
                    logger.info(cbcProxyMsg.msg_data)
                requestData.set_cbcProxyMsg(cbcProxyMsg)

                if isinstance(req_data_dict, dict):
                    for k, v in req_data_dict.items():
                        req_data_dict[k] = action(v)
                requestData.set_req_data(req_data_dict)
                requestData.set_post_res_data(str_to_dict(record['post_response_data']))
                case.requestDataList.append(requestData)
                # 每个请求的自定义断言
                if record['expect_result'] is None or record['expect_result'] == '':
                    continue
                case.expect_dict[requestData] = str_to_dict(record['expect_result'])
    return testCaseList


def getTestCaseById(case_id):
    """
    获取用例对象
    """
    fp = get_abs_path(CBSConfig.TEST_DATA_DIR + '/用例数据.xlsx')
    records = sheet_to_list(fp)
    tc = None
    for record in records:
        if record['case_id'] != case_id and tc is None:
            continue
        # 已处理完用例包含的数据，直接结束循环;
        if record['case_id'] != case_id and tc is not None:
            return tc
        if tc is None:
            # 初始化testCase类
            tc = TestCase(case_id)
        # 如果TC对象不为空
        rd = getRequestDataById(record['request_id'])
        if rd is None:
            continue
        # 处理请求数据
        requestData = copy.deepcopy(rd)
        requestData.set_username(record['user_name'])
        req_data_dict = str_to_dict(record['request_data'])
        # 新增响应代理报文
        cbcProxyMsg = getCbcProxyMsgById(record['msg_id'])
        # 代理报文的更新，存在全量更新的问题，待修复
        upd_msg_data = record['msg_data']
        if cbcProxyMsg is not None:
            if upd_msg_data is not None and len(upd_msg_data) > 0:
                cbcProxyMsg.set_msg_data(upd_dict_data(cbcProxyMsg.msg_data, record['msg_data']))
                cbcProxyMsg.get_msg_xml(rd.req_name)
            logger.info(cbcProxyMsg.msg_data)
        requestData.set_cbcProxyMsg(cbcProxyMsg)
        # 请求报文的数据处理
        if isinstance(req_data_dict, dict):
            for k, v in req_data_dict.items():
                req_data_dict[k] = action(v)
        requestData.set_req_data(req_data_dict)
        # 响应的处理
        requestData.set_post_res_data(str_to_dict(record['post_response_data']))
        tc.requestDataList.append(requestData)
        # 每个请求的自定义断言
        if record['expect_result'] is None or record['expect_result'] == '':
            continue
        tc.expect_dict[requestData] = str_to_dict(record['expect_result'])
    return tc


def getTestPlan(sheet_name=None):
    """
    执行测试计划
    :param sheet_name:
    """
    fp = CBSConfig.TEST_DATA_DIR + '/测试计划.xlsx'
    records = sheet_to_list(fp, sheet_name)
    testPlan = TestPlan()
    for record in records:
        tc = getTestCaseById(record['case_id'])
        if tc is not None:
            tc.set_case_name(record['case_name'])
            tc.set_status(int(record['case_status']))
        if int(record['exec_status']) == 1 and tc.status == 1 and tc is not None:
            testPlan.execCaseList.append(tc)
    return testPlan


def exec_case_by_id(case_id):
    """
    通过case_id来执行测试用例
    :param case_id:
    """
    # 必须是testPlan中的TestCase
    testPlan = getTestPlan()
    for tc in testPlan.execCaseList:
        if tc.case_id == case_id:
            logger.info('测试Id:' + tc.case_id + ',测试用例名称:' + tc.case_name)
            return exec_case(tc)


def exec_case(test_case):
    """
    执行测试用例
    要实现这个功能：处理每个业务请求的断言
    :param test_case:
    """
    upd_req_body = {}
    for rd in test_case.requestDataList:
        if not isinstance(rd, RequestData):
            continue
        if rd.req_data is not None and rd.req_data != '':
            rd.set_req_body(upd_dict_data(rd.req_body, rd.req_data))
        # 若当前需要上1个请求的参数，则更新到请求body的参数中
        if len(upd_req_body) > 0:
            # logger.info(upd_req_body)
            rd.set_req_body(upd_dict_data(rd.req_body, upd_req_body))
            # logger.info(rd.req_body)
        cookie = get_user_cookie(rd.username)
        cbs_req = CBSRequest(rd.child_url, rd.req_body, cookie)
        # 在发送请求前把代理报文生成,当监听到传到CBC的报文时候，主动发送过去
        if rd.req_method == 'post':
            res = cbs_req.post()
        # 断言处理
        res_body = bytes_to_dict(res.content)
        if rd in test_case.expect_dict.keys():
            req_expect_dict = test_case.expect_dict[rd]
            # if 只要1个请求结果和预期结果不通过，则该条测试案例不通过
            for erk, erv in req_expect_dict.items():
                if erv != jsonpath_util.get_value(res_body, erk):
                    return False
        # 把当前请求的响应结果所需要的字段取出来，临时存放到upd_req_body这个字典中
        if rd.post_res_data is not None and rd.post_res_data != '':
            upd_req_body = {}
            # 正则表达式取出指定的字段值
            for key, value in rd.post_res_data.items():
                pattern = None
                if key != jsonpath_util.get_paths(value)[-1]:
                    pattern = r'(?<=%s=)\w{10}' % key
                upd_value = jsonpath_util.get_value(res_body, value, pattern)
                upd_req_body[key] = upd_value
        else:
            upd_req_body = {}
    return True


def getCbcProxyMsgById(msg_id):
    """
    :param msg_id:
    """
    fp = CBSConfig.TEST_DATA_DIR + '代理报文模板.xlsx'
    for record in sheet_to_list(fp):
        if record['msg_id'] == msg_id:
            proxyMsg = CbcProxyMsg(record['msg_id'])
            proxyMsg.set_msg_name(record['msg_name'])
            proxyMsg.set_msg_path(record['msg_path'])
            proxyMsg.set_msg_bank_type(record['msg_bank_type'])
            xmlParser = minidom.parse(proxyMsg.msg_path)
            proxyMsg.parse_msg_xml(xmlParser)
            return proxyMsg


def getCbcProxyMsgByNameAndBankType(name, bankType):
    """
    通过请求报文的银行类型和报文名找到对应的代理报文
    :param name:
    :param bankType:
    """
    fp = get_abs_path(CBSConfig.TEST_DATA_DIR + '代理报文模板.xlsx')
    for record in sheet_to_list(fp):
        if record['msg_name'] == name and record['msg_bank_type'] == bankType:
            proxyMsg = CbcProxyMsg(msg_name=name, bank_type=bankType)
            proxyMsg.set_msg_path(record['msg_path'])
            return proxyMsg
